#include "stdafx.h"
#include "CppUnitTest.h"

#include "user_contract.h"
#include "user_base.h"
#include "user_type_traits.h"
#include <vex/core/make_raw_handle.h>
#include <vex/core/make_intrusive_handle.h>
#include <vex/core/make_unique_handle.h>

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

namespace tests { namespace handle_from_base_meta {
    
    namespace vc = vex::core;
    namespace vcc = vex::core::contract;
    namespace vci = vex::core::implementation;

    TEST_CLASS(handle_from_base_meta)
    {
        BEGIN_TEST_CLASS_ATTRIBUTE()
            TEST_CLASS_ATTRIBUTE(L"Module", L"tests.core.handle_from_base_meta")
        END_TEST_CLASS_ATTRIBUTE();
    public:
        template<class TExpType>
        void make_raw_handle_returns_correct_type_impl()
        {
            Assert::IsTrue(std::is_convertible<
                decltype(vex::make_raw_handle<user_base>()),
                user_base*
            >::value);

            Assert::IsTrue(std::is_base_of<
                user_base,
                TExpType
            >::value);
        }

        template<class TExpType, class TOwnership>
        void make_raw_handle_ext_returns_correct_type_impl()
        {
            Assert::IsTrue(std::is_convertible<
                decltype(vex::make_raw_handle_ext<user_base, TOwnership>()),
                user_base*
            >::value, wlog_message()
            << "expected:" << std::endl << typeid(user_base*).name() << std::endl
            << "got:" << std::endl << typeid(decltype(vex::make_raw_handle_ext<user_base, TOwnership>())).name() << std::endl | as_string);

            Assert::IsTrue(std::is_base_of<
                user_base,
                TExpType
            >::value);
        }


        TEST_METHOD(make_raw_handle_returns_correct_type)
        {
            this->make_raw_handle_returns_correct_type_impl<
                vex::handle_from_base<user_base> 
            >();
        }

        TEST_METHOD(make_raw_handle_ext_returns_correct_type)
        {
            using namespace vex::core::implementation;

            this->make_raw_handle_ext_returns_correct_type_impl<
                vex::handle_from_base<user_base, vex::shared_synchronized>,
                vex::shared_synchronized
            >();

            this->make_raw_handle_ext_returns_correct_type_impl<
                vex::handle_from_base<user_base, vex::shared>,
                vex::shared
            >();

            this->make_raw_handle_ext_returns_correct_type_impl<
                vex::handle_from_base<user_base, vex::unique>,
                vex::unique
            >();

            this->make_raw_handle_ext_returns_correct_type_impl<
                vex::handle_from_base<user_base, vex::unmanaged>,
                vex::unmanaged
            >();
        }
    };
}}
